package dev.ece.core.cells.decal;

import java.io.InputStream;
import java.nio.FloatBuffer;

import org.lwjgl.opengl.GL20;

import dev.ece.core.shader.Shader;
import dev.ece.core.texture.FBOS;
import dev.ece.core.texture.Texture;
import dev.ece.util.GLUtils;
import dev.ece.util.lib.Matrix4f;
import dev.ece.util.tools.BufferBuilder;

public class DecalShader extends Shader {

	protected final static FloatBuffer BUFFER = BufferBuilder.buildFloatBuffer(64);
	
	private int decalSizeHandler;
	
	private int textureHandler;
	
	private int eceGlPositionHandler;
	
	private int eceGlGameDataHandler;
	
	private int eceInvertModelViewMatrixHandler;
	
	private static DecalShader defaultDecalShader;
	
	public static DecalShader getDefaultDecalShader() {
		if(defaultDecalShader == null) {
			defaultDecalShader = new DecalShader(
					DecalShader.class.getClassLoader().getResourceAsStream("shaders/defer/decal.vert"),
					DecalShader.class.getClassLoader().getResourceAsStream("shaders/defer/decal.frag"));
		}
		return defaultDecalShader;
	}
	
	public DecalShader(InputStream vertexShaderInputStream, InputStream pixelShaderInputStream) {
		super(vertexShaderInputStream, pixelShaderInputStream);
	}

	public DecalShader(
			String vertexShaderSource, 
			String pixelShaderSource) {
		super(vertexShaderSource, pixelShaderSource);
	}
	
	@Override
	protected void onInitializeHandler(int program) {
		eceInvertModelViewMatrixHandler = glGetUniformLocation("ece_InvertModelViewMatrix");
		decalSizeHandler = glGetUniformLocation("decalSize");
		eceGlPositionHandler = glGetUniformLocation("eceGlPosition");
		eceGlGameDataHandler = glGetUniformLocation("eceGlGameData");
		textureHandler = glGetUniformLocation("texture");
	}

	@Override
	protected void onBindAttribLocations(int program) {
		bindAttribLocation("ece_Vertex");
	}

	public void glTexture(Texture texture) {
		GL20.glUniform1i(textureHandler, texture.bind(0));
	}
	
	public void glDefer(FBOS defer) {
		GL20.glUniform1i(eceGlPositionHandler, defer.getTextures()[0].bind(1));
		GL20.glUniform1i(eceGlGameDataHandler, defer.getTextures()[3].bind(2));
	}
	
	public void glDecalSize(float decalSize) {
		GL20.glUniform1f(decalSizeHandler, decalSize);
	}
	
	public void glEceInvertModelViewMatrix() {
		Matrix4f matrix = new Matrix4f();
		matrix.set(GLUtils.getModelViewMatrix());
		matrix.invert();
		matrix.store(BUFFER);
		BUFFER.rewind();
		GL20.glUniformMatrix4fv(eceInvertModelViewMatrixHandler, false, BUFFER);
	}
	
	@Override
	public void clearup() {
		GL20.glDeleteShader(decalSizeHandler);
		GL20.glDeleteShader(textureHandler);
		GL20.glDeleteShader(eceGlPositionHandler);
		GL20.glDeleteShader(eceGlGameDataHandler);
		GL20.glDeleteShader(eceInvertModelViewMatrixHandler);
		super.clearup();
	}

}
